home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / amitcp / netinet / ip_input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  29.8 KB  |  1,172 lines

  1. RCS_ID_C="$Id: ip_input.c,v 1.15 1993/06/04 11:16:15 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * HISTORY
  8.  * $Log: ip_input.c,v $
  9.  * Revision 1.15  1993/06/04  11:16:15  jraja
  10.  * Fixes for first public release.
  11.  *
  12.  * Revision 1.14  1993/05/29  21:21:29  jraja
  13.  * Removed all occurances of GATEWAY (now handled by GATEWAY configurable
  14.  * variable), commented out use of if_matrix, since no-one needs it and
  15.  * it may write past its memory.
  16.  *
  17.  * Revision 1.13  1993/05/17  00:16:44  ppessi
  18.  * Changed RCS version. Added rcsid.
  19.  *
  20.  * Revision 1.12  1993/04/24  23:22:04  jraja
  21.  * Removed #ifdef NOALIGN, now using straight structure copies.
  22.  *
  23.  * Revision 1.11  93/04/24  22:51:31  22:51:31  jraja (Jarno Tapio Rajahalme)
  24.  * Removed #ifdef USECLUSTERS (now using clusters always)
  25.  * 
  26.  * Revision 1.10  93/04/05  19:06:07  19:06:07  jraja (Jarno Tapio Rajahalme)
  27.  * Changed storage of the spl functions  return values to type spl_t.
  28.  * Added include for conf.h to every .c file.
  29.  * 
  30.  * Revision 1.9  93/03/22  16:59:13  16:59:13  jraja (Jarno Tapio Rajahalme)
  31.  * Changed bcopy()s and bzero()s with word aligned pointers to
  32.  * aligned_b(copy|zero) ar aligned_b(copy|zero)_const. The latter is for calls
  33.  * in which the size is constant.
  34.  * These can be disabled by defining NOALIGN.
  35.  *  Converted bcopys doing structure copies (on aligned pointers) to structure
  36.  * assignments, since at least SASC produces better code with assignment.
  37.  * 
  38.  * Revision 1.8  93/03/13  17:14:21  17:14:21  ppessi (Pekka Pessi)
  39.  * Fixed bugs with variable initialization.
  40.  * 
  41.  * Revision 1.7  93/03/05  03:20:06  03:20:06  ppessi (Pekka Pessi)
  42.  * Compiles with SASC. Initial test version.
  43.  * 
  44.  * Revision 1.6  93/03/04  12:14:13  12:14:13  jraja (Jarno Tapio Rajahalme)
  45.  * Added casts to printfs.
  46.  * 
  47.  * Revision 1.5  93/03/03  21:39:50  21:39:50  jraja (Jarno Tapio Rajahalme)
  48.  * Moved some data definitions from ip_var.h to here.
  49.  * 
  50.  * Revision 1.4  93/03/03  20:17:45  20:17:45  jraja (Jarno Tapio Rajahalme)
  51.  * Added include for kern/uipc_domain_protos.h.
  52.  * 
  53.  * Revision 1.3  93/03/02  18:30:39  18:30:39  too (Tomi Ollila)
  54.  * Changed %? to %l? on format strings
  55.  * 
  56.  * Revision 1.2  93/02/26  09:03:21  09:03:21  jraja (Jarno Tapio Rajahalme)
  57.  * Made this compile with ANSI C (added prototypes).
  58.  * chaged malloc to bsd_malloc on function ip_init().
  59.  * Added in_addr argument with phony address to icmp_error() call in 
  60.  * function ip_dooptions (it is not used by icmp_error in this case).
  61.  * Added initialization of variable 'code' in function ip_forward, since it
  62.  * might have been used withou initialization.
  63.  * Commented out mbuf cluster dependant code, since clusters are not 
  64.  * implemented (yet).
  65.  * 
  66.  * Revision 1.1  92/11/17  16:29:43  16:29:43  jraja (Jarno Tapio Rajahalme)
  67.  * Initial revision
  68.  *
  69.  */
  70.  
  71. /*
  72.  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  73.  * All rights reserved.
  74.  *
  75.  * Redistribution and use in source and binary forms, with or without
  76.  * modification, are permitted provided that the following conditions
  77.  * are met:
  78.  * 1. Redistributions of source code must retain the above copyright
  79.  *    notice, this list of conditions and the following disclaimer.
  80.  * 2. Redistributions in binary form must reproduce the above copyright
  81.  *    notice, this list of conditions and the following disclaimer in the
  82.  *    documentation and/or other materials provided with the distribution.
  83.  * 3. All advertising materials mentioning features or use of this software
  84.  *    must display the following acknowledgement:
  85.  *    This product includes software developed by the University of
  86.  *    California, Berkeley and its contributors.
  87.  * 4. Neither the name of the University nor the names of its contributors
  88.  *    may be used to endorse or promote products derived from this software
  89.  *    without specific prior written permission.
  90.  *
  91.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  92.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  93.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  94.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  95.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  96.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  97.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  98.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  99.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  100.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  101.  * SUCH DAMAGE.
  102.  *
  103.  *    @(#)ip_input.c    7.19 (Berkeley) 5/25/91
  104.  */
  105.  
  106. #include <conf.h>
  107.  
  108. #include <sys/param.h>
  109. #include <sys/systm.h>
  110. #include <sys/malloc.h>
  111. #include <sys/mbuf.h>
  112. #include <sys/domain.h>
  113. #include <sys/protosw.h>
  114. #include <sys/socket.h>
  115. #include <sys/errno.h>
  116. #include <sys/time.h>
  117. #include <sys/kernel.h>
  118. #include <sys/synch.h>
  119.  
  120. #include <net/if.h>
  121. #include <net/route.h>
  122.  
  123. #include <netinet/in.h>
  124. #include <netinet/in_systm.h>
  125. #include <netinet/ip.h>
  126. #include <netinet/in_pcb.h>
  127. #include <netinet/in_var.h>
  128. #include <netinet/ip_var.h>
  129. #include <netinet/ip_icmp.h>
  130.  
  131. #include <netinet/ip_input_protos.h>
  132. #include <netinet/ip_output_protos.h>
  133. #include <netinet/ip_icmp_protos.h>
  134. #include <netinet/in_cksum_protos.h>
  135. #include <netinet/in_protos.h>
  136. #include <kern/uipc_domain_protos.h>
  137.  
  138. #ifndef    IPFORWARDING
  139. #define    IPFORWARDING    0
  140. #endif
  141. #ifndef    IPSENDREDIRECTS
  142. #define    IPSENDREDIRECTS    1
  143. #endif
  144. #ifndef IPPRINTFS
  145. #define IPPRINTFS 0
  146. #endif
  147.  
  148. /* These three are now accessed from the configuration module
  149.  */
  150. int    ipforwarding = IPFORWARDING;
  151. int    ipsendredirects = IPSENDREDIRECTS;
  152. int    ipprintfs = IPPRINTFS;        /* this has effect only if DIAGNOSTIC */
  153.  
  154. struct    ipstat    ipstat = {0};    /* ip statistics */
  155. struct    ipq    ipq = {0};    /* ip reass. queue */
  156. u_short    ip_id = {0};        /* ip packet ctr, for ids */
  157. struct    ifqueue    ipintrq = {0};    /* ip packet input queue */
  158.  
  159. extern    struct domain inetdomain;
  160. extern    struct protosw inetsw[];
  161. u_char    ip_protox[IPPROTO_MAX] = {0};
  162. int    ipqmaxlen = IFQ_MAXLEN;
  163. struct    in_ifaddr *in_ifaddr  = NULL; /* first inet address */
  164.  
  165. /*
  166.  * We need to save the IP options in case a protocol wants to respond
  167.  * to an incoming packet over the same route if the packet got here
  168.  * using IP source routing.  This allows connection establishment and
  169.  * maintenance when the remote end is on a network that is not known
  170.  * to us.
  171.  */
  172. int    ip_nhops = 0;
  173. static    struct ip_srcrt {
  174.     struct    in_addr dst;            /* final destination */
  175.     char    nop;                /* one NOP to align */
  176.     char    srcopt[IPOPT_OFFSET + 1];    /* OPTVAL, OLEN and OFFSET */
  177.     struct    in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
  178. } ip_srcrt;
  179.  
  180. #if USE_IF_MATRIX
  181. extern    int if_index;
  182. u_long    *ip_ifmatrix = NULL;
  183. #endif
  184.  
  185. /*
  186.  * IP initialization: fill in IP protocol switch table.
  187.  * All protocols not implemented in kernel go to raw IP protocol handler.
  188.  */
  189. void
  190. ip_init()
  191. {
  192.     register struct protosw *pr;
  193.     register int i;
  194.  
  195.     pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
  196.     if (pr == 0)
  197.         panic("ip_init");
  198.     for (i = 0; i < IPPROTO_MAX; i++)
  199.         ip_protox[i] = pr - inetsw;
  200.     for (pr = inetdomain.dom_protosw;
  201.         pr < inetdomain.dom_protoswNPROTOSW; pr++)
  202.         if (pr->pr_domain->dom_family == PF_INET &&
  203.             pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
  204.             ip_protox[pr->pr_protocol] = pr - inetsw;
  205.     ipq.next = ipq.prev = &ipq;
  206.         {
  207.         struct timeval time;
  208.         get_time(&time);
  209.         ip_id = time.tv_sec & 0xffff;
  210.     }
  211.     ipintrq.ifq_maxlen = ipqmaxlen;
  212.  
  213. #if USE_IF_MATRIX
  214.     This does not work, since if_index is not constant, but actually
  215.     increases after this is done! So change this before enabling
  216.     (if_index is defined in net/if.c)
  217.  
  218.     i = (if_index + 1) * (if_index + 1) * sizeof (u_long);
  219.     if ((ip_ifmatrix = (u_long *) bsd_malloc(i, M_RTABLE, M_WAITOK)) == 0)
  220.         panic("no memory for ip_ifmatrix");
  221. #endif
  222. }
  223.  
  224. struct    ip *ip_reass();
  225. struct    sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
  226. struct    route ipforward_rt = { 0 };
  227.  
  228. /*
  229.  * Ip input routine.  Checksum and byte swap header.  If fragmented
  230.  * try to reassemble.  Process options.  Pass to next level.
  231.  */
  232. void
  233. ipintr()
  234. {
  235.     register struct ip *ip;
  236.     register struct mbuf *m;
  237.     register struct ipq *fp;
  238.     register struct in_ifaddr *ia;
  239.     int hlen;
  240.     spl_t s;
  241.  
  242. next:
  243.     /*
  244.      * Get next datagram off input queue and get IP header
  245.      * in first mbuf.
  246.      */
  247.     s = splimp();
  248.     IF_DEQUEUE(&ipintrq, m);
  249.     splx(s);
  250.     if (m == 0)
  251.         return;
  252. #if    DIAGNOSTIC
  253.     if ((m->m_flags & M_PKTHDR) == 0)
  254.         panic("ipintr no HDR");
  255. #endif
  256.     /*
  257.      * If no IP addresses have been set yet but the interfaces
  258.      * are receiving, can't do anything with incoming packets yet.
  259.      */
  260.     if (in_ifaddr == NULL)
  261.         goto bad;
  262.     ipstat.ips_total++;
  263.     if (m->m_len < sizeof (struct ip) &&
  264.         (m = m_pullup(m, sizeof (struct ip))) == 0) {
  265.         ipstat.ips_toosmall++;
  266.         goto next;
  267.     }
  268.     ip = mtod(m, struct ip *);
  269.     hlen = ip->ip_hl << 2;
  270.     if (hlen < sizeof(struct ip)) {    /* minimum header length */
  271.         ipstat.ips_badhlen++;
  272.         goto bad;
  273.     }
  274.     if (hlen > m->m_len) {
  275.         if ((m = m_pullup(m, hlen)) == 0) {
  276.             ipstat.ips_badhlen++;
  277.             goto next;
  278.         }
  279.         ip = mtod(m, struct ip *);
  280.     }
  281.     if (ip->ip_sum = in_cksum(m, hlen)) {
  282.         ipstat.ips_badsum++;
  283.         goto bad;
  284.     }
  285.  
  286.     /*
  287.      * Convert fields to host representation.
  288.      */
  289.     NTOHS(ip->ip_len);
  290.     if (ip->ip_len < hlen) {
  291.         ipstat.ips_badlen++;
  292.         goto bad;
  293.     }
  294.     NTOHS(ip->ip_id);
  295.     NTOHS(ip->ip_off);
  296.  
  297.     /*
  298.      * Check that the amount of data in the buffers
  299.      * is as at least much as the IP header would have us expect.
  300.      * Trim mbufs if longer than we expect.
  301.      * Drop packet if shorter than we expect.
  302.      */
  303.     if (m->m_pkthdr.len < ip->ip_len) {
  304.         ipstat.ips_tooshort++;
  305.         goto bad;
  306.     }
  307.     if (m->m_pkthdr.len > ip->ip_len) {
  308.         if (m->m_len == m->m_pkthdr.len) {
  309.             m->m_len = ip->ip_len;
  310.             m->m_pkthdr.len = ip->ip_len;
  311.         } else
  312.             m_adj(m, ip->ip_len - m->m_pkthdr.len);
  313.     }
  314.  
  315.     /*
  316.      * Process options and, if not destined for us,
  317.      * ship it on.  ip_dooptions returns 1 when an
  318.      * error was detected (causing an icmp message
  319.      * to be sent and the original packet to be freed).
  320.      */
  321.     ip_nhops = 0;        /* for source routed packets */
  322.     if (hlen > sizeof (struct ip) && ip_dooptions(m))
  323.         goto next;
  324.  
  325.     /*
  326.      * Check our list of addresses, to see if the packet is for us.
  327.      */
  328.     for (ia = in_ifaddr; ia; ia = ia->ia_next) {
  329. #define    satosin(sa)    ((struct sockaddr_in *)(sa))
  330.  
  331.         if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
  332.             goto ours;
  333.         if (
  334. #ifdef    DIRECTED_BROADCAST
  335.             ia->ia_ifp == m->m_pkthdr.rcvif &&
  336. #endif
  337.             (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
  338.             u_long t;
  339.  
  340.             if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
  341.                 ip->ip_dst.s_addr)
  342.                 goto ours;
  343.             if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
  344.                 goto ours;
  345.             /*
  346.              * Look for all-0's host part (old broadcast addr),
  347.              * either for subnet or net.
  348.              */
  349.             t = ntohl(ip->ip_dst.s_addr);
  350.             if (t == ia->ia_subnet)
  351.                 goto ours;
  352.             if (t == ia->ia_net)
  353.                 goto ours;
  354.         }
  355.     }
  356.     if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
  357.         goto ours;
  358.     if (ip->ip_dst.s_addr == INADDR_ANY)
  359.         goto ours;
  360.  
  361.     /*
  362.      * Not for us; forward if possible and desirable.
  363.      */
  364.     if (ipforwarding == 0) {
  365.         ipstat.ips_cantforward++;
  366.         m_freem(m);
  367.     } else
  368.         ip_forward(m, 0);
  369.     goto next;
  370.  
  371. ours:
  372.     /*
  373.      * If offset or IP_MF are set, must reassemble.
  374.      * Otherwise, nothing need be done.
  375.      * (We could look in the reassembly queue to see
  376.      * if the packet was previously fragmented,
  377.      * but it's not worth the time; just let them time out.)
  378.      */
  379.     if (ip->ip_off &~ IP_DF) {
  380.         if (m->m_flags & M_EXT) {        /* XXX */
  381.             if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
  382.                 ipstat.ips_toosmall++;
  383.                 goto next;
  384.             }
  385.             ip = mtod(m, struct ip *);
  386.         }
  387.         /*
  388.          * Look for queue of fragments
  389.          * of this datagram.
  390.          */
  391.         for (fp = ipq.next; fp != &ipq; fp = fp->next)
  392.             if (ip->ip_id == fp->ipq_id &&
  393.                 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
  394.                 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
  395.                 ip->ip_p == fp->ipq_p)
  396.                 goto found;
  397.         fp = 0;
  398. found:
  399.  
  400.         /*
  401.          * Adjust ip_len to not reflect header,
  402.          * set ip_mff if more fragments are expected,
  403.          * convert offset of this to bytes.
  404.          */
  405.         ip->ip_len -= hlen;
  406.         ((struct ipasfrag *)ip)->ipf_mff = 0;
  407.         if (ip->ip_off & IP_MF)
  408.             ((struct ipasfrag *)ip)->ipf_mff = 1;
  409.         ip->ip_off <<= 3;
  410.  
  411.         /*
  412.          * If datagram marked as having more fragments
  413.          * or if this is not the first fragment,
  414.          * attempt reassembly; if it succeeds, proceed.
  415.          */
  416.         if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
  417.             ipstat.ips_fragments++;
  418.             ip = ip_reass((struct ipasfrag *)ip, fp);
  419.             if (ip == 0)
  420.                 goto next;
  421.             else
  422.                 ipstat.ips_reassembled++;
  423.             m = dtom(ip);
  424.         } else
  425.             if (fp)
  426.                 ip_freef(fp);
  427.     } else
  428.         ip->ip_len -= hlen;
  429.  
  430.     /*
  431.      * Switch out to protocol's input routine.
  432.      */
  433.     ipstat.ips_delivered++;
  434.     (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
  435.     goto next;
  436. bad:
  437.     m_freem(m);
  438.     goto next;
  439. }
  440.  
  441. /*
  442.  * Take incoming datagram fragment and try to
  443.  * reassemble it into whole datagram.  If a chain for
  444.  * reassembly of this datagram already exists, then it
  445.  * is given as fp; otherwise have to make a chain.
  446.  */
  447. struct ip *
  448. ip_reass(ip, fp)
  449.     register struct ipasfrag *ip;
  450.     register struct ipq *fp;
  451. {
  452.     register struct mbuf *m = dtom(ip);
  453.     register struct ipasfrag *q;
  454.     struct mbuf *t;
  455.     int hlen = ip->ip_hl << 2;
  456.     int i, next;
  457.  
  458.     /*
  459.      * Presence of header sizes in mbufs
  460.      * would confuse code below.
  461.      */
  462.     m->m_data += hlen;
  463.     m->m_len -= hlen;
  464.  
  465.     /*
  466.      * If first fragment to arrive, create a reassembly queue.
  467.      */
  468.     if (fp == 0) {
  469.         if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
  470.             goto dropfrag;
  471.         fp = mtod(t, struct ipq *);
  472.         insque(fp, &ipq);
  473.         fp->ipq_ttl = IPFRAGTTL;
  474.         fp->ipq_p = ip->ip_p;
  475.         fp->ipq_id = ip->ip_id;
  476.         fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
  477.         fp->ipq_src = ((struct ip *)ip)->ip_src;
  478.         fp->ipq_dst = ((struct ip *)ip)->ip_dst;
  479.         q = (struct ipasfrag *)fp;
  480.         goto insert;
  481.     }
  482.  
  483.     /*
  484.      * Find a segment which begins after this one does.
  485.      */
  486.     for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
  487.         if (q->ip_off > ip->ip_off)
  488.             break;
  489.  
  490.     /*
  491.      * If there is a preceding segment, it may provide some of
  492.      * our data already.  If so, drop the data from the incoming
  493.      * segment.  If it provides all of our data, drop us.
  494.      */
  495.     if (q->ipf_prev != (struct ipasfrag *)fp) {
  496.         i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
  497.         if (i > 0) {
  498.             if (i >= ip->ip_len)
  499.                 goto dropfrag;
  500.             m_adj(dtom(ip), i);
  501.             ip->ip_off += i;
  502.             ip->ip_len -= i;
  503.         }
  504.     }
  505.  
  506.     /*
  507.      * While we overlap succeeding segments trim them or,
  508.      * if they are completely covered, dequeue them.
  509.      */
  510.     while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
  511.         i = (ip->ip_off + ip->ip_len) - q->ip_off;
  512.         if (i < q->ip_len) {
  513.             q->ip_len -= i;
  514.             q->ip_off += i;
  515.             m_adj(dtom(q), i);
  516.             break;
  517.         }
  518.         q = q->ipf_next;
  519.         m_freem(dtom(q->ipf_prev));
  520.         ip_deq(q->ipf_prev);
  521.     }
  522.  
  523. insert:
  524.     /*
  525.      * Stick new segment in its place;
  526.      * check for complete reassembly.
  527.      */
  528.     ip_enq(ip, q->ipf_prev);
  529.     next = 0;
  530.     for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
  531.         if (q->ip_off != next)
  532.             return (0);
  533.         next += q->ip_len;
  534.     }
  535.     if (q->ipf_prev->ipf_mff)
  536.         return (0);
  537.  
  538.     /*
  539.      * Reassembly is complete; concatenate fragments.
  540.      */
  541.     q = fp->ipq_next;
  542.     m = dtom(q);
  543.     t = m->m_next;
  544.     m->m_next = 0;
  545.     m_cat(m, t);
  546.     q = q->ipf_next;
  547.     while (q != (struct ipasfrag *)fp) {
  548.         t = dtom(q);
  549.         q = q->ipf_next;
  550.         m_cat(m, t);
  551.     }
  552.  
  553.     /*
  554.      * Create header for new ip packet by
  555.      * modifying header of first packet;
  556.      * dequeue and discard fragment reassembly header.
  557.      * Make header visible.
  558.      */
  559.     ip = fp->ipq_next;
  560.     ip->ip_len = next;
  561.     ((struct ip *)ip)->ip_src = fp->ipq_src;
  562.     ((struct ip *)ip)->ip_dst = fp->ipq_dst;
  563.     remque(fp);
  564.     (void) m_free(dtom(fp));
  565.     m = dtom(ip);
  566.     m->m_len += (ip->ip_hl << 2);
  567.     m->m_data -= (ip->ip_hl << 2);
  568.     /* some debugging cruft by sklower, below, will go away soon */
  569.     if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
  570.         register int plen = 0;
  571.         for (t = m; m; m = m->m_next)
  572.             plen += m->m_len;
  573.         t->m_pkthdr.len = plen;
  574.     }
  575.     return ((struct ip *)ip);
  576.  
  577. dropfrag:
  578.     ipstat.ips_fragdropped++;
  579.     m_freem(m);
  580.     return (0);
  581. }
  582.  
  583. /*
  584.  * Free a fragment reassembly header and all
  585.  * associated datagrams.
  586.  */
  587. void
  588. ip_freef(fp)
  589.     struct ipq *fp;
  590. {
  591.     register struct ipasfrag *q, *p;
  592.  
  593.     for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
  594.         p = q->ipf_next;
  595.         ip_deq(q);
  596.         m_freem(dtom(q));
  597.     }
  598.     remque(fp);
  599.     (void) m_free(dtom(fp));
  600. }
  601.  
  602. /*
  603.  * Put an ip fragment on a reassembly chain.
  604.  * Like insque, but pointers in middle of structure.
  605.  */
  606. void
  607. ip_enq(p, prev)
  608.     register struct ipasfrag *p, *prev;
  609. {
  610.  
  611.     p->ipf_prev = prev;
  612.     p->ipf_next = prev->ipf_next;
  613.     prev->ipf_next->ipf_prev = p;
  614.     prev->ipf_next = p;
  615. }
  616.  
  617. /*
  618.  * To ip_enq as remque is to insque.
  619.  */
  620. void
  621. ip_deq(p)
  622.     register struct ipasfrag *p;
  623. {
  624.  
  625.     p->ipf_prev->ipf_next = p->ipf_next;
  626.     p->ipf_next->ipf_prev = p->ipf_prev;
  627. }
  628.  
  629. /*
  630.  * IP timer processing;
  631.  * if a timer expires on a reassembly
  632.  * queue, discard it.
  633.  */
  634. void
  635. ip_slowtimo()
  636. {
  637.     register struct ipq *fp;
  638.     spl_t s = splnet();
  639.  
  640.     fp = ipq.next;
  641.     if (fp == 0) {
  642.         splx(s);
  643.         return;
  644.     }
  645.     while (fp != &ipq) {
  646.         --fp->ipq_ttl;
  647.         fp = fp->next;
  648.         if (fp->prev->ipq_ttl == 0) {
  649.             ipstat.ips_fragtimeout++;
  650.             ip_freef(fp->prev);
  651.         }
  652.     }
  653.     splx(s);
  654. }
  655.  
  656. /*
  657.  * Drain off all datagram fragments.
  658.  */
  659. void
  660. ip_drain()
  661. {
  662.  
  663.     while (ipq.next != &ipq) {
  664.         ipstat.ips_fragdropped++;
  665.         ip_freef(ipq.next);
  666.     }
  667. }
  668.  
  669. extern struct in_ifaddr *ifptoia();
  670. struct in_ifaddr *ip_rtaddr();
  671.  
  672. /*
  673.  * Do option processing on a datagram,
  674.  * possibly discarding it if bad options are encountered,
  675.  * or forwarding it if source-routed.
  676.  * Returns 1 if packet has been forwarded/freed,
  677.  * 0 if the packet should be processed further.
  678.  */
  679. int
  680. ip_dooptions(m)
  681.     struct mbuf *m;
  682. {
  683.     register struct ip *ip = mtod(m, struct ip *);
  684.     register u_char *cp;
  685.     register struct ip_timestamp *ipt;
  686.     register struct in_ifaddr *ia;
  687.     int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
  688.     struct in_addr *sin, dest;
  689.     n_time ntime;
  690.     
  691.     cp = (u_char *)(ip + 1);
  692.     cnt = (ip->ip_hl << 2) - sizeof (struct ip);
  693.     for (; cnt > 0; cnt -= optlen, cp += optlen) {
  694.         opt = cp[IPOPT_OPTVAL];
  695.         if (opt == IPOPT_EOL)
  696.             break;
  697.         if (opt == IPOPT_NOP)
  698.             optlen = 1;
  699.         else {
  700.             optlen = cp[IPOPT_OLEN];
  701.             if (optlen <= 0 || optlen > cnt) {
  702.                 code = &cp[IPOPT_OLEN] - (u_char *)ip;
  703.                 goto bad;
  704.             }
  705.         }
  706.         switch (opt) {
  707.  
  708.         default:
  709.             break;
  710.  
  711.         /*
  712.          * Source routing with record.
  713.          * Find interface with current destination address.
  714.          * If none on this machine then drop if strictly routed,
  715.          * or do nothing if loosely routed.
  716.          * Record interface address and bring up next address
  717.          * component.  If strictly routed make sure next
  718.          * address is on directly accessible net.
  719.          */
  720.         case IPOPT_LSRR:
  721.         case IPOPT_SSRR:
  722.             if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
  723.                 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
  724.                 goto bad;
  725.             }
  726.             ipaddr.sin_addr = ip->ip_dst;
  727.             ia = (struct in_ifaddr *)
  728.                 ifa_ifwithaddr((struct sockaddr *)&ipaddr);
  729.             if (ia == 0) {
  730.                 if (opt == IPOPT_SSRR) {
  731.                     type = ICMP_UNREACH;
  732.                     code = ICMP_UNREACH_SRCFAIL;
  733.                     goto bad;
  734.                 }
  735.                 /*
  736.                  * Loose routing, and not at next destination
  737.                  * yet; nothing to do except forward.
  738.                  */
  739.                 break;
  740.             }
  741.             off--;            /* 0 origin */
  742.             if (off > optlen - sizeof(struct in_addr)) {
  743.                 /*
  744.                  * End of source route.  Should be for us.
  745.                  */
  746.                 save_rte(cp, ip->ip_src);
  747.                 break;
  748.             }
  749.             /*
  750.              * locate outgoing interface
  751.              */
  752.             bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
  753.                 sizeof(ipaddr.sin_addr));
  754.             if (opt == IPOPT_SSRR) {
  755. #define    INA    struct in_ifaddr *
  756. #define    SA    struct sockaddr *
  757.                 if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
  758.                 ia = in_iaonnetof(in_netof(ipaddr.sin_addr));
  759.             } else
  760.                 ia = ip_rtaddr(ipaddr.sin_addr);
  761.             if (ia == 0) {
  762.                 type = ICMP_UNREACH;
  763.                 code = ICMP_UNREACH_SRCFAIL;
  764.                 goto bad;
  765.             }
  766.             ip->ip_dst = ipaddr.sin_addr;
  767.             bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
  768.                 (caddr_t)(cp + off), sizeof(struct in_addr));
  769.             cp[IPOPT_OFFSET] += sizeof(struct in_addr);
  770.             forward = 1;
  771.             break;
  772.  
  773.         case IPOPT_RR:
  774.             if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
  775.                 code = &cp[IPOPT_OFFSET] - (u_char *)ip;
  776.                 goto bad;
  777.             }
  778.             /*
  779.              * If no space remains, ignore.
  780.              */
  781.             off--;            /* 0 origin */
  782.             if (off > optlen - sizeof(struct in_addr))
  783.                 break;
  784.             ipaddr.sin_addr = ip->ip_dst;
  785.             /*
  786.              * locate outgoing interface; if we're the destination,
  787.              * use the incoming interface (should be same).
  788.              */
  789.             if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
  790.                 (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
  791.                 type = ICMP_UNREACH;
  792.                 code = ICMP_UNREACH_HOST;
  793.                 goto bad;
  794.             }
  795.             bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
  796.                 (caddr_t)(cp + off), sizeof(struct in_addr));
  797.             cp[IPOPT_OFFSET] += sizeof(struct in_addr);
  798.             break;
  799.  
  800.         case IPOPT_TS:
  801.             code = cp - (u_char *)ip;
  802.             ipt = (struct ip_timestamp *)cp;
  803.             if (ipt->ipt_len < 5)
  804.                 goto bad;
  805.             if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
  806.                 if (++ipt->ipt_oflw == 0)
  807.                     goto bad;
  808.                 break;
  809.             }
  810.             sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
  811.             switch (ipt->ipt_flg) {
  812.  
  813.             case IPOPT_TS_TSONLY:
  814.                 break;
  815.  
  816.             case IPOPT_TS_TSANDADDR:
  817.                 if (ipt->ipt_ptr + sizeof(n_time) +
  818.                     sizeof(struct in_addr) > ipt->ipt_len)
  819.                     goto bad;
  820.                 ia = ifptoia(m->m_pkthdr.rcvif);
  821.                 *sin = IA_SIN(ia)->sin_addr;
  822.                 ipt->ipt_ptr += sizeof(struct in_addr);
  823.                 break;
  824.  
  825.             case IPOPT_TS_PRESPEC:
  826.                 if (ipt->ipt_ptr + sizeof(n_time) +
  827.                     sizeof(struct in_addr) > ipt->ipt_len)
  828.                     goto bad;
  829.                 ipaddr.sin_addr = *sin;
  830.                 if (ifa_ifwithaddr((SA)&ipaddr) == 0)
  831.                     continue;
  832.                 ipt->ipt_ptr += sizeof(struct in_addr);
  833.                 break;
  834.  
  835.             default:
  836.                 goto bad;
  837.             }
  838.             ntime = iptime();
  839.             bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
  840.                 sizeof(n_time));
  841.             ipt->ipt_ptr += sizeof(n_time);
  842.         }
  843.     }
  844.     if (forward) {
  845.         ip_forward(m, 1);
  846.         return (1);
  847.     } else
  848.         return (0);
  849. bad:
  850.     icmp_error(m, type, code, dest); /* dest is not used */
  851.     return (1);
  852. }
  853.  
  854. /*
  855.  * Given address of next destination (final or next hop),
  856.  * return internet address info of interface to be used to get there.
  857.  */
  858. struct in_ifaddr *
  859. ip_rtaddr(dst)
  860.      struct in_addr dst;
  861. {
  862.     register struct sockaddr_in *sin;
  863.  
  864.     sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
  865.  
  866.     if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
  867.         if (ipforward_rt.ro_rt) {
  868.             RTFREE(ipforward_rt.ro_rt);
  869.             ipforward_rt.ro_rt = 0;
  870.         }
  871.         sin->sin_family = AF_INET;
  872.         sin->sin_len = sizeof(*sin);
  873.         sin->sin_addr = dst;
  874.  
  875.         rtalloc(&ipforward_rt);
  876.     }
  877.     if (ipforward_rt.ro_rt == 0)
  878.         return ((struct in_ifaddr *)0);
  879.     return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
  880. }
  881.  
  882. /*
  883.  * Save incoming source route for use in replies,
  884.  * to be picked up later by ip_srcroute if the receiver is interested.
  885.  */
  886. void
  887. save_rte(option, dst)
  888.     u_char *option;
  889.     struct in_addr dst;
  890. {
  891.     unsigned olen;
  892.  
  893.     olen = option[IPOPT_OLEN];
  894. #if DIAGNOSTIC
  895.     if (ipprintfs)
  896.         printf("save_rte: olen %ld\n", olen);
  897. #endif
  898.     if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
  899.         return;
  900.     bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
  901.     ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
  902.     ip_srcrt.dst = dst;
  903. }
  904.  
  905. /*
  906.  * Retrieve incoming source route for use in replies,
  907.  * in the same form used by setsockopt.
  908.  * The first hop is placed before the options, will be removed later.
  909.  */
  910. struct mbuf *
  911. ip_srcroute()
  912. {
  913.     register struct in_addr *p, *q;
  914.     register struct mbuf *m;
  915.  
  916.     if (ip_nhops == 0)
  917.         return ((struct mbuf *)0);
  918.     m = m_get(M_DONTWAIT, MT_SOOPTS);
  919.     if (m == 0)
  920.         return ((struct mbuf *)0);
  921.  
  922. #define OPTSIZ    (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
  923.  
  924.     /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
  925.     m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
  926.         OPTSIZ;
  927. #if DIAGNOSTIC
  928.     if (ipprintfs)
  929.         printf("ip_srcroute: nhops %ld mlen %ld", ip_nhops, m->m_len);
  930. #endif
  931.  
  932.     /*
  933.      * First save first hop for return route
  934.      */
  935.     p = &ip_srcrt.route[ip_nhops - 1];
  936.     *(mtod(m, struct in_addr *)) = *p--;
  937. #if DIAGNOSTIC
  938.     if (ipprintfs)
  939.         printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr));
  940. #endif
  941.  
  942.     /*
  943.      * Copy option fields and padding (nop) to mbuf.
  944.      */
  945.     ip_srcrt.nop = IPOPT_NOP;
  946.     ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
  947.     aligned_bcopy_const((caddr_t)&ip_srcrt.nop,
  948.         mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ);
  949.     q = (struct in_addr *)(mtod(m, caddr_t) +
  950.         sizeof(struct in_addr) + OPTSIZ);
  951. #undef OPTSIZ
  952.     /*
  953.      * Record return path as an IP source route,
  954.      * reversing the path (pointers are now aligned).
  955.      */
  956.     while (p >= ip_srcrt.route) {
  957. #if DIAGNOSTIC
  958.         if (ipprintfs)
  959.             printf(" %lx", ntohl(q->s_addr));
  960. #endif
  961.         *q++ = *p--;
  962.     }
  963.     /*
  964.      * Last hop goes to final destination.
  965.      */
  966.     *q = ip_srcrt.dst;
  967. #if DIAGNOSTIC
  968.     if (ipprintfs)
  969.         printf(" %lx\n", ntohl(q->s_addr));
  970. #endif
  971.     return (m);
  972. }
  973.  
  974. /*
  975.  * Strip out IP options, at higher
  976.  * level protocol in the kernel.
  977.  * Second argument is buffer to which options
  978.  * will be moved, and return value is their length.
  979.  * XXX should be deleted; last arg currently ignored.
  980.  */
  981. void
  982. ip_stripoptions(m, mopt)
  983.     register struct mbuf *m;
  984.     struct mbuf *mopt;
  985. {
  986.     register int i;
  987.     struct ip *ip = mtod(m, struct ip *);
  988.     register caddr_t opts;
  989.     int olen;
  990.  
  991.     olen = (ip->ip_hl<<2) - sizeof (struct ip);
  992.     opts = (caddr_t)(ip + 1);
  993.     i = m->m_len - (sizeof (struct ip) + olen);
  994.     aligned_bcopy(opts  + olen, opts, (unsigned)i);
  995.     m->m_len -= olen;
  996.     if (m->m_flags & M_PKTHDR)
  997.         m->m_pkthdr.len -= olen;
  998.     ip->ip_hl = sizeof(struct ip) >> 2;
  999. }
  1000.  
  1001. u_char inetctlerrmap[PRC_NCMDS] = {
  1002.     0,        0,        0,        0,
  1003.     0,        EMSGSIZE,    EHOSTDOWN,    EHOSTUNREACH,
  1004.     EHOSTUNREACH,    EHOSTUNREACH,    ECONNREFUSED,    ECONNREFUSED,
  1005.     EMSGSIZE,    EHOSTUNREACH,    0,        0,
  1006.     0,        0,        0,        0,
  1007.     ENOPROTOOPT
  1008. };
  1009.  
  1010. /*
  1011.  * Forward a packet.  If some error occurs return the sender
  1012.  * an icmp packet.  Note we can't always generate a meaningful
  1013.  * icmp message because icmp doesn't have a large enough repertoire
  1014.  * of codes and types.
  1015.  *
  1016.  * If not forwarding, just drop the packet.  This could be confusing
  1017.  * if ipforwarding was zero but some routing protocol was advancing
  1018.  * us as a gateway to somewhere.  However, we must let the routing
  1019.  * protocol deal with that.
  1020.  *
  1021.  * The srcrt parameter indicates whether the packet is being forwarded
  1022.  * via a source route.
  1023.  */
  1024. void
  1025. ip_forward(m, srcrt)
  1026.     struct mbuf *m;
  1027.     int srcrt;
  1028. {
  1029.     register struct ip *ip = mtod(m, struct ip *);
  1030.     register struct sockaddr_in *sin;
  1031.     register struct rtentry *rt;
  1032.     int error, type = 0, code = 0;
  1033.     struct mbuf *mcopy;
  1034.     struct in_addr dest;
  1035.  
  1036.     dest.s_addr = 0;
  1037. #if DIAGNOSTIC
  1038.     if (ipprintfs)
  1039.         printf("forward: src %lx dst %lx ttl %lx\n", ip->ip_src.s_addr,
  1040.             ip->ip_dst.s_addr, ip->ip_ttl);
  1041. #endif
  1042.     if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) {
  1043.         ipstat.ips_cantforward++;
  1044.         m_freem(m);
  1045.         return;
  1046.     }
  1047.     HTONS(ip->ip_id);
  1048.     if (ip->ip_ttl <= IPTTLDEC) {
  1049.         icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest);
  1050.         return;
  1051.     }
  1052.     ip->ip_ttl -= IPTTLDEC;
  1053.  
  1054.     sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
  1055.     if ((rt = ipforward_rt.ro_rt) == 0 ||
  1056.         ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
  1057.         if (ipforward_rt.ro_rt) {
  1058.             RTFREE(ipforward_rt.ro_rt);
  1059.             ipforward_rt.ro_rt = 0;
  1060.         }
  1061.         sin->sin_family = AF_INET;
  1062.         sin->sin_len = sizeof(*sin);
  1063.         sin->sin_addr = ip->ip_dst;
  1064.  
  1065.         rtalloc(&ipforward_rt);
  1066.         if (ipforward_rt.ro_rt == 0) {
  1067.             icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest);
  1068.             return;
  1069.         }
  1070.         rt = ipforward_rt.ro_rt;
  1071.     }
  1072.  
  1073.     /*
  1074.      * Save at most 64 bytes of the packet in case
  1075.      * we need to generate an ICMP message to the src.
  1076.      */
  1077.     mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
  1078.  
  1079. #if USE_IF_MATRIX
  1080.     ip_ifmatrix[rt->rt_ifp->if_index +
  1081.          if_index * m->m_pkthdr.rcvif->if_index]++;
  1082. #endif
  1083.     /*
  1084.      * If forwarding packet using same interface that it came in on,
  1085.      * perhaps should send a redirect to sender to shortcut a hop.
  1086.      * Only send redirect if source is sending directly to us,
  1087.      * and if packet was not source routed (or has any options).
  1088.      * Also, don't send redirect if forwarding using a default route
  1089.      * or a route modified by a redirect.
  1090.      */
  1091. #define    satosin(sa)    ((struct sockaddr_in *)(sa))
  1092.     if (rt->rt_ifp == m->m_pkthdr.rcvif &&
  1093.         (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
  1094.         satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
  1095.         ipsendredirects && !srcrt) {
  1096.         struct in_ifaddr *ia;
  1097.         u_long src = ntohl(ip->ip_src.s_addr);
  1098.         u_long dst = ntohl(ip->ip_dst.s_addr);
  1099.  
  1100.         if ((ia = ifptoia(m->m_pkthdr.rcvif)) &&
  1101.            (src & ia->ia_subnetmask) == ia->ia_subnet) {
  1102.             if (rt->rt_flags & RTF_GATEWAY)
  1103.             dest = satosin(rt->rt_gateway)->sin_addr;
  1104.             else
  1105.             dest = ip->ip_dst;
  1106.             /*
  1107.              * If the destination is reached by a route to host,
  1108.              * is on a subnet of a local net, or is directly
  1109.              * on the attached net (!), use host redirect.
  1110.              * (We may be the correct first hop for other subnets.)
  1111.              */
  1112. #define    RTA(rt)    ((struct in_ifaddr *)(rt->rt_ifa))
  1113.             type = ICMP_REDIRECT;
  1114.             if ((rt->rt_flags & RTF_HOST) ||
  1115.                 (rt->rt_flags & RTF_GATEWAY) == 0)
  1116.                 code = ICMP_REDIRECT_HOST;
  1117.             else if (RTA(rt)->ia_subnetmask != RTA(rt)->ia_netmask &&
  1118.                 (dst & RTA(rt)->ia_netmask) ==  RTA(rt)->ia_net)
  1119.                 code = ICMP_REDIRECT_HOST;
  1120.             else
  1121.                 code = ICMP_REDIRECT_NET;
  1122. #if DIAGNOSTIC
  1123.             if (ipprintfs)
  1124.                 printf("redirect (%ld) to %lx\n", code, dest.s_addr);
  1125. #endif
  1126.         }
  1127.     }
  1128.  
  1129.     error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING);
  1130.     if (error)
  1131.         ipstat.ips_cantforward++;
  1132.     else {
  1133.         ipstat.ips_forward++;
  1134.         if (type)
  1135.             ipstat.ips_redirectsent++;
  1136.         else {
  1137.             if (mcopy)
  1138.                 m_freem(mcopy);
  1139.             return;
  1140.         }
  1141.     }
  1142.     if (mcopy == NULL)
  1143.         return;
  1144.     switch (error) {
  1145.  
  1146.     case 0:                /* forwarded, but need redirect */
  1147.         /* type, code set above */
  1148.         break;
  1149.  
  1150.     case ENETUNREACH:        /* shouldn't happen, checked above */
  1151.     case EHOSTUNREACH:
  1152.     case ENETDOWN:
  1153.     case EHOSTDOWN:
  1154.     default:
  1155.         type = ICMP_UNREACH;
  1156.         code = ICMP_UNREACH_HOST;
  1157.         break;
  1158.  
  1159.     case EMSGSIZE:
  1160.         type = ICMP_UNREACH;
  1161.         code = ICMP_UNREACH_NEEDFRAG;
  1162.         ipstat.ips_cantfrag++;
  1163.         break;
  1164.  
  1165.     case ENOBUFS:
  1166.         type = ICMP_SOURCEQUENCH;
  1167.         code = 0;
  1168.         break;
  1169.     }
  1170.     icmp_error(mcopy, type, code, dest);
  1171. }
  1172.